/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = wtc_tfmh.c                                         */
/*  NOTE      =                                                    */
/*  DATE      = 2015/08/13 by songbb                               */
/*******************************************************************/

#include "frreport_comm.h"
#include "conntrack.h"
#include "frct_comm.h"

#include "wtc_core.h"
#include "wtc_comm.h"
#include "wtc_mar.h"
#include "wtc_tfmh.h"
#include "wtc_tcm.h"
#include "wtc_tch.h"

/*******************************************************************************
*  FUNC     :  解析dataxfer请求
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (WTC私有的session)
*           :  *p_st_wtc_packet                         (WTC数据包)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int wtc_tfmh_dom(Conntrack *p_st_conn
                , L7session_wtc *p_st_sess
                , L7_wtc_packet *p_st_wtc_packet
                , Frhash_header *p_st_hash_report)
{
    char *p_domain_name = NULL;
    unsigned int ui_domain_name_len = 0;
    char tident2_helper[78] = {'\0'};
    char p_scratch[150] = {'\0'};
    unsigned int ui_flag = 0;
    unsigned int ui_timeout = 0;

    if (bytebuff_skip(p_st_wtc_packet->p_st_packet, APM_WTC_PKT_HEADER_LEN) != FR_SUCC)
        goto error;

    if (p_st_wtc_packet->i_use_old_protocol == APM_WTC_FLAG_UNSET && wtc_detect_use_old_protocol_by_string(p_st_wtc_packet) != FR_SUCC)
        goto error;

    if (p_st_wtc_packet->i_use_old_protocol == FR_YES)
    {
        if (wtc_mar_decode_vector_string(p_st_wtc_packet, tident2_helper, 32, &p_domain_name, &ui_domain_name_len) != FR_SUCC)
            goto error;
    }
    else
    {
        if (wtc_mar_decode_string(p_st_sess, p_scratch, 150, p_st_wtc_packet, &p_domain_name, &ui_domain_name_len) != FR_SUCC)
            goto error;
    }
    if (p_st_wtc_packet->i_is_req == FR_YES)
    {
        wtc_free((void **) &(p_st_sess->p_client_domainid));
        p_st_sess->p_client_domainid = frstrdup(p_domain_name);
    }
    else
    {
        wtc_free((void **) &(p_st_sess->p_service_domainid));
        p_st_sess->p_service_domainid = frstrdup(p_domain_name);
    }
    WTC_PRINT_FATAL("p_domain_name:[%s]\n", p_domain_name);

    if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_flag, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    // 这里，opcode == 1 || opcode == 4 ? timeout : tpevent，因为没用到这个值，只当作timeout处理
    if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_timeout, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    // TODO: 这里继续

    wtc_free((void **) &p_domain_name);
    return FR_SUCC;
error:
    wtc_free((void **) &p_domain_name);
    return FR_FAIL;
}

FR_STATIC void __wtc_tfmh_analyze_direction(Conntrack *p_st_conn
                                            , Apm_packet *p_analyze_in
                                            , L7session_wtc *p_st_sess
                                            , L7_wtc_packet *p_st_wtc_packet)
{
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_wtc_private *p_st_session_private = (L7session_wtc_private *) frct_get_session_private(p_st_session);
    L7_wtc_stmt *p_st_wtc_stmt = p_st_session_private->p_st_wtc_stmt;
    int i_direction = FR_DIRECT_UNKNOWN;
    char *p_payload = NULL;
    unsigned int ui_payload_len = 0;
#if APM_WTC_DBG
    char arr_ip_src[56], arr_ip_dst[56];
    snprintf(arr_ip_src, sizeof(arr_ip_src), "%s", int_ntoa(p_analyze_in->src_ip));
    snprintf(arr_ip_dst, sizeof(arr_ip_src), "%s", int_ntoa(p_analyze_in->dst_ip));
#endif

    if (p_st_wtc_packet == NULL)
    {
        WTC_PRINT_CRIT("get packet error\n\n");
        return;
    }

    ui_payload_len = (unsigned int) bytebuff_length(p_st_wtc_packet->p_st_packet);

    if (bytebuff_show(p_st_wtc_packet->p_st_packet, 0, ui_payload_len, &p_payload) != FR_SUCC)
    {
        WTC_PRINT_CRIT("get packet error\n\n");
        return;
    }

    if (wtc_tfmh_fad(p_payload, ui_payload_len, &i_direction) != FR_SUCC)
    {
        WTC_PRINT_CRIT("wtc_tfmh_fad error\n\n");
        goto error;
    }

    if (i_direction == FR_DIRECT_CLIENT2SRV)
    {
        if (p_st_sess->dst_ip == 0 || p_st_sess->dst_port == 0)
        {
            p_st_sess->dst_ip = p_analyze_in->dst_ip;
            p_st_sess->dst_port = p_analyze_in->dst_port;
        }
        else if (p_st_sess->dst_ip != p_analyze_in->dst_ip && p_st_sess->dst_port != p_analyze_in->dst_port)
        {
            p_st_sess->dst_ip = p_analyze_in->dst_ip;
            p_st_sess->dst_port = p_analyze_in->dst_port;
            memset(&p_st_wtc_stmt->st_req_end_timestamp, 0x0, sizeof(struct timeval));
            memset(&p_st_wtc_stmt->st_resp_start_timestamp, 0x0, sizeof(struct timeval));
            p_st_wtc_packet->i_is_req = FR_YES;
            WTC_PRINT_CRIT("Set Server use CLIENT2SRV:[%s:%d]\n\n", arr_ip_dst, p_analyze_in->dst_port);
            if (frcap_set_cs_srv(p_st_conn, p_analyze_in->dst_ip, p_analyze_in->dst_port) != FR_SUCC)
                goto error;
        }
        else
            WTC_PRINT_CRIT("nothing to do\n\n");

        if (p_analyze_in->i_direction == FR_DIRECT_UNKNOWN || frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
        {
            WTC_PRINT_CRIT("Set Server:[%s:%d]\n", arr_ip_dst, p_analyze_in->dst_port);
            if (frcap_set_cs_srv(p_st_conn, p_analyze_in->dst_ip, p_analyze_in->dst_port) != FR_SUCC)
                goto error;
        }
    }
    else if (i_direction == FR_DIRECT_SRV2CLIENT)
    {
        if (p_st_sess->dst_ip == 0 || p_st_sess->dst_port == 0)
        {
            p_st_sess->dst_ip = p_analyze_in->src_ip;
            p_st_sess->dst_port = p_analyze_in->src_port;
        }
        else if (p_st_sess->dst_ip != p_analyze_in->src_ip && p_st_sess->dst_port != p_analyze_in->src_port)
        {
            p_st_sess->dst_ip = p_analyze_in->src_ip;
            p_st_sess->dst_port = p_analyze_in->src_port;
            wtc_init_stmt(p_st_conn, p_st_session_private->p_st_wtc_stmt);
            p_st_wtc_packet->i_is_req = FR_NO;
            WTC_PRINT_CRIT("Set Server use SRV2CLIENT:[%s:%d]\n\n", arr_ip_src, p_analyze_in->src_port);
            if (frcap_set_cs_srv(p_st_conn, p_analyze_in->src_ip, p_analyze_in->src_port) != FR_SUCC)
                goto error;
        }
        else
            WTC_PRINT_CRIT("nothing to do\n\n");

        if (p_analyze_in->i_direction == FR_DIRECT_UNKNOWN || frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
        {
            WTC_PRINT_CRIT("Set Server:[%s:%d]\n", arr_ip_src, p_analyze_in->src_port);
            if (frcap_set_cs_srv(p_st_conn, p_analyze_in->src_ip, p_analyze_in->src_port) != FR_SUCC)
                goto error;
        }
    }

error:
    wtc_free((void **) &p_payload);
    return;
}

/*******************************************************************************
*  FUNC     :  解析dataxfer请求
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (WTC私有的session)
*           :  *p_st_wtc_packet                         (WTC数据包)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int wtc_tfmh(Conntrack *p_st_conn
            , Apm_packet *p_analyze_in
            , L7session_wtc *p_st_sess
            , L7_wtc_packet *p_st_wtc_packet
            , Frhash_header *p_st_hash_report)
{
    WTC_PRINT_INFO("wtc_tfmh...\n");
    L7_session *p_st_session = frct_get_session(p_st_conn);
    L7session_wtc_private *p_st_session_private = (L7session_wtc_private *) frct_get_session_private(p_st_session);
    L7_wtc_stmt *p_st_wtc_stmt = p_st_session_private->p_st_wtc_stmt;
    unsigned int ui_magic = 0;
    unsigned int ui_ltype_idx = 0;
    unsigned int ui_tmfmh_flag = 0;
    WTC_tch_header st_tch_header;
    char *p_mbstring = NULL;
    unsigned int ui_mbstring_len = 0;
    Frreport_body_data *p_st_body = NULL;
    char *p_field_name = NULL;
    int i_field_name_len = 0;
    L7_wtc_mbstring *p_st_wtc_mbstring = NULL;
    Frlist_node *p_st_mbstring_node = NULL;

//    if (p_st_wtc_packet->i_is_req == FR_NO &&
//        (p_st_session_private->p_report_comm == NULL ||
//        p_st_session_private->p_report_req == NULL))
//    {
//        WTC_PRINT_ALERT("Ignore this response\n");
//        return FR_SUCC;
//    }

    __wtc_tfmh_analyze_direction(p_st_conn, p_analyze_in, p_st_sess, p_st_wtc_packet);

    if (p_st_wtc_packet->i_is_req == FR_YES)
        wtc_init_stmt(p_st_conn, p_st_session_private->p_st_wtc_stmt);

    p_st_wtc_stmt->ui_arg_count = 0;

    if (bytebuff_skip(p_st_wtc_packet->p_st_packet, APM_WTC_PKT_HEADER_LEN) != FR_SUCC)
        goto error;

    if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_magic, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_ltype_idx, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    if (bytebuff_get_int(p_st_wtc_packet->p_st_packet, 4, &ui_tmfmh_flag, BYTE_BIG_ENDIAN) != FR_SUCC)
        goto error;

    WTC_PRINT_ALERT("tmfmh_flag:[0x%08x]\n", ui_tmfmh_flag);
    if ((ui_tmfmh_flag & 0x80000) == 0)
    {
        if (wtc_read_tcm_by_idx(p_st_conn, p_analyze_in, p_st_sess, p_st_wtc_packet, ui_ltype_idx, &p_st_body) != FR_SUCC)
            goto error;
    }

    wtc_free((void **) &(p_st_sess->p_codeset_encoding));

    while (bytebuff_remaining(p_st_wtc_packet->p_st_packet) > 0)
    {
        memset(&st_tch_header, 0x00, sizeof(WTC_tch_header));
        if (wtc_read_tch(p_st_wtc_packet, &st_tch_header) != FR_SUCC)
            goto error;
        if (wtc_read_tcm_by_hdr(p_st_conn, p_analyze_in, p_st_sess, p_st_wtc_packet, st_tch_header) != FR_SUCC)
            goto error;
    }

    if (p_st_sess->p_codeset_encoding != NULL)
    {
        p_st_mbstring_node = frlist_pop(p_st_wtc_stmt->p_list_mbstring);
        while (p_st_mbstring_node)
        {
            p_st_wtc_mbstring = (L7_wtc_mbstring *) FRLIST_GET_NODE_DATA(p_st_mbstring_node);

            i_field_name_len = strlen(p_st_wtc_packet->i_is_req == FR_YES ? APM_DTS_REPORT_REQ_ARG_DATA :
                                      APM_DTS_REPORT_RESP_ARG_DATA) + 16;
            if ((p_field_name = (char *) frmalloc(i_field_name_len * sizeof(char))) == NULL)
            {
                WTC_MALLOCK_ERR;
                goto error;
            }
            snprintf(p_field_name, (size_t) i_field_name_len, "%s%u",
                     p_st_wtc_packet->i_is_req == FR_YES ? APM_DTS_REPORT_REQ_ARG_DATA : APM_DTS_REPORT_RESP_ARG_DATA,
                     p_st_wtc_mbstring->ui_index);

            if (p_st_wtc_mbstring->p_mbstring == NULL || p_st_wtc_mbstring->ui_mbstring_len <= 0)
            {
                if (frreport_body_l7_add_str(p_st_body, p_field_name, "") != FR_SUCC)
                    goto error;
                p_st_wtc_stmt->ui_arg_count++;
            }
            else
            {
                if (wtc_mar_get_mbstring(p_st_sess->p_codeset_encoding, p_st_wtc_mbstring->p_mbstring,
                                         p_st_wtc_mbstring->ui_mbstring_len, &p_mbstring, &ui_mbstring_len) != FR_SUCC)
                    goto error;
                WTC_PRINT_ALERT("%s\n", p_mbstring);

                if (frreport_body_l7_add_str(p_st_body, p_field_name, p_mbstring) != FR_SUCC)
                    goto error;
                p_st_wtc_stmt->ui_arg_count++;
                wtc_free((void **) &p_mbstring);
            }

            wtc_free((void **) &p_field_name);
            p_st_mbstring_node = frlist_pop(p_st_wtc_stmt->p_list_mbstring);
        }
    }

    // 上报commit,rollback,failure
    WTC_PRINT_DBG("opcode:[%s]\n", WTC_OPCODE2STR(p_st_wtc_stmt->ui_opcode));
    if (p_st_wtc_stmt->ui_opcode == APM_WTC_GWNW_XATMI_COMMIT ||
        p_st_wtc_stmt->ui_opcode == APM_WTC_GWNW_XATMI_ROLLBACK ||
        p_st_wtc_stmt->ui_opcode == APM_WTC_GWNW_XATMI_DONE ||
        p_st_wtc_stmt->ui_opcode == APM_WTC_GWNW_XATMI_FAILURE)
    {
        if (p_st_body == NULL)
        {
            if ((p_st_body = frreport_body_new_l7(p_st_conn)) == NULL)
                goto error;
            if (p_st_wtc_stmt->ui_opcode == APM_WTC_GWNW_XATMI_COMMIT)
            {
                if (frreport_body_l7_add_str(p_st_body, APM_DTS_REPORT_REQ_SERVICE_METHOD, "commit") != FR_SUCC)
                    goto error;
                if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, "commit") != FR_SUCC)
                    goto error;
            }
            else if (p_st_wtc_stmt->ui_opcode == APM_WTC_GWNW_XATMI_ROLLBACK)
            {
                if (frreport_body_l7_add_str(p_st_body, APM_DTS_REPORT_REQ_SERVICE_METHOD, "rollback") != FR_SUCC)
                    goto error;
                if (frreport_body_l7_add_str(p_st_body, APM_REPORT_KEY_TRANS_TITLE, "rollback") != FR_SUCC)
                    goto error;
            }
        }
    }

    if (p_st_body != NULL)
    {
        if (p_st_wtc_packet->i_is_req == FR_YES)
        {
            if (wtc_report_msg_data_req(p_st_conn, p_st_sess, p_st_wtc_packet, p_st_body, p_st_hash_report) != FR_SUCC)
                goto error;
        }
        else
        {
            if (wtc_report_msg_data_resp(p_st_conn, p_st_sess, p_st_wtc_packet, p_st_body, p_st_hash_report) != FR_SUCC)
                goto error;
        }
    }

    wtc_free((void **) &p_field_name);
    return FR_SUCC;
error:
    wtc_free((void **) &p_field_name);
    frreport_body_free(&p_st_body);
    return FR_FAIL;
}

int wtc_tfmh_fad(char *p_payload
                , unsigned int ui_payload_len
                , int *p_i_direction)
{
    WTC_PRINT_INFO("wtc_tfmh_fad...\n");
    unsigned int ui_ltype_idx = 0;
    unsigned int ui_tmfmh_flag = 0;
    WTC_tch_header st_tch_header;

    unsigned int ui_offset = APM_WTC_PKT_HEADER_LEN;

    if (wtc_skip_int(p_payload, ui_payload_len, &ui_offset) != FR_SUCC) // ui_magic
        goto error;

    if (wtc_get_int(p_payload, ui_payload_len, &ui_offset, &ui_ltype_idx) != FR_SUCC)
        goto error;
    if (wtc_get_int(p_payload, ui_payload_len, &ui_offset, &ui_tmfmh_flag) != FR_SUCC)
        goto error;

    WTC_PRINT_ALERT("tmfmh_flag:[0x%08x]\n", ui_tmfmh_flag);
    if ((ui_tmfmh_flag & 0x80000) == 0)
    {
        if (wtc_read_tcm_by_idx_fad(ui_ltype_idx, p_payload, ui_payload_len, &ui_offset) != FR_SUCC)
            goto error;
    }

    while (wtc_remaining(ui_payload_len, &ui_offset) > 0)
    {
        memset(&st_tch_header, 0x00, sizeof(WTC_tch_header));
        if (wtc_read_tch_fad(p_payload, ui_payload_len, &ui_offset, &st_tch_header) != FR_SUCC)
            goto error;
        if (wtc_read_tcm_by_hdr_fad(p_payload, ui_payload_len, &ui_offset, st_tch_header, p_i_direction) != FR_SUCC)
            goto error;
        if (*p_i_direction != FR_DIRECT_UNKNOWN)
            return FR_SUCC;
    }

    return FR_SUCC;
error:
    return FR_FAIL;
}
